﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Runtime.Remoting;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using EasyHook;
using MassPokerTool.Infrastructure.Core.Commands;
using MassPokerTool.Infrastructure.Hooking;
using MassPokerTool.Infrastructure.Hooking.Target;
using MassPokerTool.Infrastructure.Logging;
using Microsoft.Practices.Prism.ViewModel;

namespace MassPokerTool.Modules.Main.ViewModels
{
    public class TestViewModel : NotificationObject
    {
        private readonly ILogger _log;
        private string _channelName = null;
        private readonly DispatcherTimer _refreshTimer;

        public TestViewModel(ILogger log, IList<ITargetApplication> targetApplications)
        {
            _log = log;
            AppsManager.Initialize(targetApplications);
            _refreshTimer = new DispatcherTimer()
                {
                    IsEnabled = true,
                    Interval = TimeSpan.FromSeconds(2)
                };
            _refreshTimer.Tick += RefreshOnTick;
            InjectCommand = new DelegateCommand(InjectExecute);
            PrepareForInjection();
        }

        private void RefreshOnTick(object sender, EventArgs eventArgs)
        {
            AppsManager.Refresh();
            RaisePropertyChanged(() => Applications);
            RaisePropertyChanged(() => Messages);
        }

        private void PrepareForInjection()
        {
            try
            {
                Config.Register(
                    "A FileMon like demo application.",
                    "MassPokerTool.exe",
                    "MassPokerTool.Inject.dll",
                    "MassPokerTool.Infrastructure.dll");
                // leave it singleton!!!
                RemoteHooking.IpcCreateServer<MassPokerInterface>(ref _channelName, WellKnownObjectMode.Singleton);
            }
            catch (ApplicationException)
            {
                MessageBox.Show("This is an administrative task!", "Permission denied...", MessageBoxButton.OK);
                Process.GetCurrentProcess().Kill();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Fatal error...", MessageBoxButton.OK);
                Process.GetCurrentProcess().Kill();
            }
        }

        private void InjectExecute(object o)
        {
            var cbo = o as CheckBox;
            if (cbo != null)
            {
                var application = cbo.DataContext as ITargetApplication;
                if (application != null)
                {
                    try
                    {
                        if (cbo.IsChecked.GetValueOrDefault(false))
                        {
                            // make injection
                            _log.Debug("Starting injection...");
                            RemoteHooking.Inject(application.CurrentPid, "MassPokerTool.Inject.dll", "MassPokerTool.Inject.dll", _channelName, application.HooksProvider);
                            AppsManager.ConfirmInjection(application.CurrentPid);
                        }
                        else
                        {
                            // quit injection
                            _log.Debug("Quitting injection...");
                            AppsManager.QuitInjection(application.CurrentPid);
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.Error(String.Format("There was an error while connecting to target:\r\n{0}", ex.ToString()));
                    }
                }
            }
        }

        public ReadOnlyCollection<ITargetApplication> Applications
        {
            get { return AppsManager.Applications; }
        }

        public ICommand InjectCommand { get; set; }

        public ObservableCollection<Message> Messages 
        {
            get { return MessageBus.Messages; }
        } 
    }
}
